iT邦幫忙

2023 iThome 鐵人賽

DAY 20
0
自我挑戰組

Unit Test 學習路系列 第 20

Day 19: React Testing Library - findBy** 與 findAllBy**

  • 分享至 

  • xImage
  •  

今天來認識一下 findBy**findAllBy**

findBy**

  • 用途:取得指定條件的 DOM nodes,並返回一包含指定DOM node 的 Promise。
  • 何時會用到:
    當測試 DOM node 一開始不存在,但後續觸發事件而存在的情況。像是 Call API 拿到回傳資料顯示。
    當指定條件在預設 1000 毫秒 內找到,返回 fulfilled Promise;
    當找不到指定條件、符合超過一個條件,或超過預設 1000 毫秒時,返回 rejected Promise。
  • 舉例:設定時間 0.5s 使用者為登入狀態,畫面顯示登出按鈕。
export default function Applications(){
    const [isLoggedIn, setIsLoggedIn] = useState(false);

    useEffect(() => {
        setTimeout(() => setIsLoggedIn(true), 500);
    }, [])

    return(
        <>
            <h2>User Info</h2>
            {   isLoggedIn
                ? <LogOutBtn setIsLoggedIn={setIsLoggedIn} />
                : <LogInBtn setIsLoggedIn={setIsLoggedIn} />
            }
        </>
    )
}

撰寫測試:

describe("Logging", () => {
    test("Render LogOut Button When user logs in!", () => {
        render(<Applications />);

        const logOutBtn = screen.getByRole("button", {
            name: "Log Out"
        });
        expect(logOutBtn).toBeInTheDocument();
    });
});

測次結果:
FAIL src/components/logging/logging.test.tsx
● Logging › Render LogOut Button When user logs in!

TestingLibraryElementError: Unable to find an accessible element with the role "button" and name "Log Out"

將測試方法 getByRole 改成 findByRole:加入 async-await

describe("Logging", () => {
    test("Render LogOut Button When user logs in!", async() => {
        render(<Applications />);

        const logOutBtn = await screen.findByRole("button", {
            name: "Log Out"
        });
        expect(logOutBtn).toBeInTheDocument();
    });
});

測次結果:
PASS src/components/logging/logging.test.tsx


findAllBy**

  • 用途:取得指定條件的 DOM nodes,並返回一陣列包含指定DOM nodes 的 Promise。
  • 何時會用到:
    當測試 DOM node 一開始不存在,但後續觸發事件而存在的情況。像是 Call API 拿到回傳資料顯示。
    當指定條件在預設 1000 毫秒 內找到,返回 fulfilled Promise;
    當找不到指定條件、符合超過一個條件,或超過預設 1000 毫秒時,返回 rejected Promise。
  • 舉例:設定時間 0.5s 使用者為登入狀態,畫面顯示使用者喜好。
export default function Applications(){
    const [isLoggedIn, setIsLoggedIn] = useState(false);

    useEffect(() => {
        setTimeout(() => setIsLoggedIn(true), 500);
    }, [])

    return(
        <>
            <h2>User Info</h2>
            {   isLoggedIn
                ? <Hobbies hobbies={["Sleeping", "Cooking", "Eating"]}/>
                : null
            }
        </>
    )
}

撰寫測試:

describe("Hobbies By Logging State", () => {
    // 檢查 <li> 多個節點
    test("Render Listitems correctlly!", async() => {
        render(<Applications />);

        const listItemElements = await screen.findAllByRole("listitem");
        expect(listItemElements).toHaveLength(listItemElements.length);
    })
})

測次結果:
PASS src/components/hobbies/hobbies.test.tsx


find query 超過預設 1000 毫秒

我們可以透過 findBy**findAllBy**第三個參數屬性 timeout:自定義等待時間

describe("Hobbies By Logging State", () => {
    // 檢查 <li> 多個節點
    test("Render Listitems correctlly!", async() => {
        render(<Applications />);

        const listItemElements = await screen.findAllByRole(
            "listitem", 
            {}, 
            {timeout: 2000}
        );
        expect(listItemElements).toHaveLength(listItemElements.length);
    })
})

統整 RTL Queries

Query 使用時機 返回內容
getBy** getAllBy** 當測試 DOM node 是否存在的情況。 成功,返回 Element; 失敗,返回 Error。
queryBy** queryAllBy** 當測試 DOM node 是否不存在(預期條件應該不存在),但不希望測試報錯的情況。 成功,返回 Element; 失敗,返回 null。
findBy** findAllBy** 當測試 DOM node 一開始不存在,但後續觸發事件而存在的情況。 成功,返回 fulfilled Promise; 失敗,返回 rejected Promise。

參考資源


上一篇
Day 18: React Testing Library - queryBy** 與 queryAllBy**
下一篇
Day 20: `logRole`
系列文
Unit Test 學習路31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言